package com.bupt.server.obj;

import com.bupt.server.entity.Room;
import com.bupt.server.entity.Service_Record;
import com.zaxxer.hikari.util.ClockSource;

import javax.annotation.PostConstruct;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoField;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import static com.bupt.server.obj.PublicData.*;
import static java.lang.Math.max;
import static java.lang.Math.min;


public class Schedule {
    int record_id = 0;
    //@PostConstruct
    public void schedule_ac(){
            try {
                ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
                Runnable task = new Runnable() {
                    @Override
                    public void run() {

                        //开机的空调加入等待队列
                        for(int i = 1; i <= 5; ++ i) {
                            totalRoomList.get(i).PrintInfo();
                            //将刚开机的空调加入等待队列
                            if (totalRoomList.get(i).getAc_status().equals("on")) {
                                if(!waitingList.contains(i) && !serveList.contains(i)) {
                                    waitingList.add(i);
                                    totalRoomList.get(i).waitingTimer = -1;
                                }
                            }
                            //将服务队列和等待队列中被关机的空调删除
                            if (totalRoomList.get(i).getAc_status().equals("off")) {
                                if(waitingList.contains(i))
                                    waitingList.remove(Integer.valueOf(i));
                                if(serveList.contains(i))
                                    serveList.remove(Integer.valueOf(i));
                            }
                        }

                        //waitingList中需要删除的房间
                        ArrayList<Integer> removeWaiting = new ArrayList<>();
                        //waitingList中需要加入的房间
                        ArrayList<Integer> addWaiting = new ArrayList<>();
                        for(/*遍历等待队列*/Integer e1: waitingList) {
                            //当前等待的房间
                            Room waitingRoom = totalRoomList.get(e1);

                            if (/*服务队列有空闲*/serveList.size() < 3) {
                                serveList.add(e1);//注意，waitingList应该在循环之外删除掉加入serveList的房间
                                waitingRoom.serverTimer = 0;
                                removeWaiting.add(e1);
                                continue;
                            }

                            if (/*等待的服务有时间片*/waitingRoom.waitingTimer != -1)
                                //时间片-1
                                waitingRoom.waitingTimer--;

                            //取出服务队列里风速最低的一批
                            ArrayList<Integer> lowest = new ArrayList<>();
                            String minx = "high";
                            for (/*遍历服务队列*/Integer e2 : serveList) {
                                if (SpeedCompare(totalRoomList.get(e2).getSpeed(), minx) == -1) {
                                    minx = totalRoomList.get(e2).getSpeed();
                                    lowest.clear();
                                }
                                if (SpeedCompare(totalRoomList.get(e2).getSpeed(), minx) == 0) {
                                    minx = totalRoomList.get(e2).getSpeed();
                                    lowest.add(e2);
                                }
                            }
                            //选择取出风速中执行时间最长的
                            int max = -1, maxid = 0;
                            for(Integer e: lowest) {
                                if(totalRoomList.get(e).serverTimer > max) {
                                    max = totalRoomList.get(e).serverTimer;
                                    maxid = e;
                                }
                            }

                            //无空闲,请求风速与取出的进行比较
                            if(/*请求风速大于取出风速*/SpeedCompare(waitingRoom.getSpeed(), minx) == 1) {
                                //直接调入
                                serveList.remove(Integer.valueOf(maxid));
                                addWaiting.add(maxid);

                                serveList.add(e1);
                                totalRoomList.get(e1).serverTimer = 0;
                                removeWaiting.add(e1);
                            }
                            if(/*请求风速等于取出风速*/SpeedCompare(waitingRoom.getSpeed(), minx) == 0) {
                                //无时间片则分配时间片;
                                if(waitingRoom.waitingTimer == -1)
                                    waitingRoom.waitingTimer = 2;
                                //有时间片，归零了就分配
                                if(waitingRoom.waitingTimer == 0) {
                                    serveList.remove(Integer.valueOf(maxid));
                                    addWaiting.add(maxid);

                                    serveList.add(e1);
                                    totalRoomList.get(e1).serverTimer = 0;
                                    removeWaiting.add(e1);
                                }
                            }
                            if(/*请求风速小于取出风速*/SpeedCompare(waitingRoom.getSpeed(), minx) == -1)
                                //有则删除时间片;
                                if(waitingRoom.waitingTimer != -1)
                                    waitingRoom.waitingTimer = -1;
                            //等待;
                        }

                        for(Integer e: removeWaiting)
                            waitingList.remove(Integer.valueOf(e));
                        for(Integer e: addWaiting) {
                            waitingList.add(e);
                            totalRoomList.get(e).waitingTimer = -1;
                        }
                        for(Integer e: serveList)
                            totalRoomList.get(e).serverTimer ++;
                    }

                };
                // 使用executor的scheduleAtFixedRate方法来每秒运行一次任务
                ScheduledFuture<?> future = executor.scheduleAtFixedRate(task, 0, 1, TimeUnit.SECONDS);
            } catch (Exception e) {
                e.printStackTrace();
            }

    }

    public void PrintRoomList(){
        synchronized (PublicData.class) {
            for (int i = 0; i < totalRoomList.size(); i++) {
                totalRoomList.get(i + 1).PrintInfo();
            }
            System.out.println();
        }
    }
    public void PrintWaitingList(){
        for(int i = 0; i < waitingList.size(); i++){
            System.out.println("waitingList: "+waitingList.get(i)+"   waitingTimer: "+totalRoomList.get(waitingList.get(i)).waitingTimer);
        }
    }

    public void PrintServeList(){
        for(int i = 0; i < serveList.size(); i++){
            System.out.println("serveList: "+serveList.get(i));
        }
    }

    public void ac_schedule_test(){
            //开机的空调加入等待队列
            for(int i = 1; i <= 5; ++ i) {
                //将刚开机的空调加入等待队列
                if (totalRoomList.get(i).getAc_status().equals("on")) {
                    if(!waitingList.contains(i) && !serveList.contains(i)) {
                        waitingList.add(i);
                        totalRoomList.get(i).waitingTimer = -1;
                    }
                }
                //将服务队列和等待队列中被关机的空调删除
                if (totalRoomList.get(i).getAc_status().equals("off")) {
                    if(waitingList.contains(i)) {
                        waitingList.remove(Integer.valueOf(i));
                        totalRoomList.get(i).setTotal_cost(totalRoomList.get(i).getTotal_cost()+PublicData.GetRoomPrice(i));
                    }
                    if(serveList.contains(i)) {
                        serveList.remove(Integer.valueOf(i));
                        totalRoomList.get(i).setTotal_cost(totalRoomList.get(i).getTotal_cost()+PublicData.GetRoomPrice(i));
                    }
                }
            }

            //waitingList中需要删除的房间
            ArrayList<Integer> removeWaiting = new ArrayList<>();
            //waitingList中需要加入的房间
//                    ArrayList<Integer> addWaiting = new ArrayList<>();

//                    for(/*遍历等待队列*/Integer e1: waitingList) {
            for(int i = 0; i < waitingList.size(); ++ i) {
                int e1 = waitingList.get(i);
                //当前等待的房间
                Room waitingRoom = totalRoomList.get(e1);

                if (/*服务队列有空闲*/serveList.size() < 3) {
                    serveList.add(e1);//注意，waitingList应该在循环之外删除掉加入serveList的房间
                    totalRoomList.get(e1).serverTimer = 0;
                    removeWaiting.add(e1);
                    continue;
                }

                if (/*等待的服务有时间片*/waitingRoom.waitingTimer != -1)
                    //时间片-1
                    waitingRoom.waitingTimer--;

                //取出服务队列里风速最低的一批
                ArrayList<Integer> lowest = new ArrayList<>();
                String minx = "high";
                for (/*遍历服务队列*/Integer e2 : serveList) {
                    if (SpeedCompare(totalRoomList.get(e2).getSpeed(), minx) == -1) {
                        minx = totalRoomList.get(e2).getSpeed();
                        lowest.clear();
                    }
                    if (SpeedCompare(totalRoomList.get(e2).getSpeed(), minx) == 0) {
                        minx = totalRoomList.get(e2).getSpeed();
                        lowest.add(e2);
                    }
                }
                //选择取出风速中执行时间最长的
                int max = -1, maxid = 0;
                for(Integer e: lowest) {
                    if(totalRoomList.get(e).serverTimer > max) {
                        max = totalRoomList.get(e).serverTimer;
                        maxid = e;
                    }
                }

                //无空闲,请求风速与取出的进行比较
                if(/*请求风速大于取出风速*/SpeedCompare(waitingRoom.getSpeed(), minx) == 1) {
                    //直接调入
                    serveList.remove(Integer.valueOf(maxid));
//                            addWaiting.add(maxid);
                    waitingList.add(maxid);
                    totalRoomList.get(maxid).waitingTimer = -1;

                    serveList.add(e1);
                    totalRoomList.get(e1).serverTimer = 0;
                    removeWaiting.add(e1);
                }
                if(/*请求风速等于取出风速*/SpeedCompare(waitingRoom.getSpeed(), minx) == 0) {
                    //无时间片则分配时间片;
                    if(waitingRoom.waitingTimer == -1)
                        waitingRoom.waitingTimer = 2;
                    //有时间片，归零了就分配
                    if(waitingRoom.waitingTimer == 0) {
                        serveList.remove(Integer.valueOf(maxid));
//                                addWaiting.add(maxid);
                        waitingList.add(maxid);
                        totalRoomList.get(maxid).waitingTimer = -1;

                        serveList.add(e1);
                        totalRoomList.get(e1).serverTimer = 0;
                        removeWaiting.add(e1);
                    }
                }
                if(/*请求风速小于取出风速*/SpeedCompare(waitingRoom.getSpeed(), minx) == -1)
                    //有则删除时间片;
                    if(waitingRoom.waitingTimer != -1)
                        waitingRoom.waitingTimer = -1;
                //等待;
            }

            for(Integer e: removeWaiting)
                waitingList.remove(Integer.valueOf(e));
//                    for(Integer e: addWaiting) {
//                        waitingList.add(e);
//                        totalRoomList.get(e).waitingTimer = -1;
//                    }
            for(Integer e: serveList)
                totalRoomList.get(e).serverTimer ++;
    }



    public void CalServiceRecord(){
        synchronized (PublicData.class) {
            for(int i = 0; i < serveList.size(); i++){
               Room room = totalRoomList.get(serveList.get(i));
                if (room.getSpeed().equals("high")) {
                    room.setTotal_air_cost(room.getTotal_air_cost() + 1f);
                } else if (room.getSpeed().equals("medium")) {
                    room.setTotal_air_cost(room.getTotal_air_cost() + 0.5f);
                } else if (room.getSpeed().equals("low")) {
                    room.setTotal_air_cost(room.getTotal_air_cost() + 0.33f);
                }
            }
        }
    }

    public void CalTemperature(){
        synchronized (PublicData.class) {
            //List<Integer> removeServeList = new ArrayList<>();
            for (int room_id : PublicData.serveList) {
                Room room = totalRoomList.get(room_id);
                if (temp.equals("heat")){
                    if (room.getAc_status().equals("on") && (room.getCurrent_temperature() < room.getTarget_temperature())) {
                        switch (room.getSpeed()) {
                            case "high" -> {
                                if (room.getCurrent_temperature() + 1f < room.getTarget_temperature()) {
                                    room.setCurrent_temperature(room.getCurrent_temperature() + 1f);
                                } else {
                                    room.setCurrent_temperature(room.getTarget_temperature());
                                }
                            }
                            case "medium" -> {
                                if (room.getCurrent_temperature() + 0.5f < room.getTarget_temperature()) {
                                    room.setCurrent_temperature(room.getCurrent_temperature() + 0.5f);
                                } else {
                                    room.setCurrent_temperature(room.getTarget_temperature());
                                }
                            }
                            case "low" -> {
                                if (room.getCurrent_temperature() + 0.33f < room.getTarget_temperature()) {
                                    room.setCurrent_temperature(room.getCurrent_temperature() + 0.33f);
                                } else {
                                    room.setCurrent_temperature(room.getTarget_temperature());
                                }
                            }
                        }
                    }
                }else{
                    if (room.getAc_status().equals("on") && (room.getCurrent_temperature() > room.getTarget_temperature())) {
                        switch (room.getSpeed()) {
                            case "high" -> {
                                if (room.getCurrent_temperature() - 1f > room.getTarget_temperature()) {
                                    room.setCurrent_temperature(room.getCurrent_temperature() - 1f);
                                } else {
                                    room.setCurrent_temperature(room.getTarget_temperature());
                                }
                            }
                            case "medium" -> {
                                if (room.getCurrent_temperature() - 0.5f > room.getTarget_temperature()) {
                                    room.setCurrent_temperature(room.getCurrent_temperature() - 0.5f);
                                } else {
                                    room.setCurrent_temperature(room.getTarget_temperature());
                                }
                            }
                            case "low" -> {
                                if (room.getCurrent_temperature() - 0.33f > room.getTarget_temperature()) {
                                    room.setCurrent_temperature(room.getCurrent_temperature() - 0.33f);
                                } else {
                                    room.setCurrent_temperature(room.getTarget_temperature());
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    public void CalServiceRecord(Integer curTime){
        synchronized (PublicData.class) {
            for(int i = 0; i < serveList.size(); i++){
                Room room = totalRoomList.get(serveList.get(i));
                if (room.getSpeed().equals("high")) {
                    room.setTotal_air_cost(room.getTotal_air_cost() + 1f);
                    room.addRecordRaw("high",curTime);
                } else if (room.getSpeed().equals("medium")) {
                    room.setTotal_air_cost(room.getTotal_air_cost() + 0.5f);
                    room.addRecordRaw("medium",curTime);
                } else if (room.getSpeed().equals("low")) {
                    room.setTotal_air_cost(room.getTotal_air_cost() + 0.33f);
                    room.addRecordRaw("low",curTime);
                }
            }
        }
    }


    public void IsHuiWen(){
        synchronized (PublicData.class) {
            if(temp.equals("heat")) {
                for (Map.Entry<Integer, Room> entry : PublicData.totalRoomList.entrySet()) {
                    Room room = entry.getValue();
                    if (room.getCurrent_temperature() > room.init_temperature && (room.getAc_status().equals("off")) || waitingList.contains(room.getRoom_id())) {
                        room.setCurrent_temperature((float) max(room.init_temperature, room.getCurrent_temperature() - 0.5));
                    }
                }
            }else{
                for (Map.Entry<Integer, Room> entry : PublicData.totalRoomList.entrySet()) {
                    Room room = entry.getValue();
                    if (room.getCurrent_temperature() < room.init_temperature &&  (room.getAc_status().equals("off")) || waitingList.contains(room.getRoom_id())) {
                        room.setCurrent_temperature((float) min(room.init_temperature, room.getCurrent_temperature() + 0.5));
                    }
                }
            }
        }
    }

    public int SpeedCompare(String speed1, String speed2) {
        int value1 = 0;
        int value2 = 0;

        switch (speed1) {
            case "low":
                value1 = 1;
                break;
            case "medium":
                value1 = 2;
                break;
            case "high":
                value1 = 3;
                break;
        }

        switch (speed2) {
            case "low":
                value2 = 1;
                break;
            case "medium":
                value2 = 2;
                break;
            case "high":
                value2 = 3;
                break;
        }

        if (value1 > value2) {
            return 1;
        } else if (value1 == value2) {
            return 0;
        } else {
            return -1;
        }
    }
}
